#pragma once

#include <iostream>
#include <map>
#include <list>

#include "CommonFunction.h"
#include "Gap.h"
class Gap;

using namespace std;

class Contig
{
public:
	Contig(void);
	Contig( int id, int length );
	virtual ~Contig(void);

	// Attributes
private:
	int m_id;		// the id of contig
	int m_length;			// the length of contig
	string m_name;			// the name of contig
	double m_cov;				// the coverage of contig
	map<int, pair<Contig*, int> > *leftEdge;		// the left edges of current contig( default orientation: + ), pair is (contig, edge size or overlap distance)
	map<int, pair<Contig*, int> > *rightEdge;		// the right edges of current contig( default orientation: + );
	int m_copyNum;					// the copy number of this contig
	int m_occu;						// the occurrence in previous gaps
	bool m_isInScaffold;			// record if this contig is in original scaffold
	list<Gap*> *m_gaps;				// record the gaps containing this contig
	string m_plusSeq;				// sequence in plus orientation, without first k-1 mers
	string m_minusSeq;				// sequence in minus orientation, without first k-1 mers
	
	// vector related parameters
	int m_startPos;
	int m_endPos;			// the start and end position of this contig on vector
	int m_vecOri;			// the orientation of this contig in vector
	bool m_ifPrintInVec;	// if this contig is printed in vector graph
	int m_stepInVecGraph;	// the step in vector graph
	bool m_isVec;			// if it is a vector contig

	// quadratic programming related
	list<int> *inEdges;				// all the in edge variables 
	list<int> *outEdges;			// all the out edge variables
	list<int> *inEdgesNew;			// in edge variables in one subgraph
	list<int> *outEdgesNew;			// out edge variables in one subgraph

	// simplification variables
	list<pair<string, string> > *m_combinedNodes;		// remember the combined nodes in this path, <ori, name>
	

	// Methods
public:
	void SetCov( double cov );
	double GetCov();
	void AddRightEdge( int contigID, Contig *contig, int size );
	void AddLeftEdge( int contigID, Contig *contig, int size );
	int GetID();
	int GetLength();
	void SetLength( int l );
	string GetName();
	// check if this contig has multiple neighbors
	bool HasMultipleNeighbors();
	int GetNumberOfNeighbors();
	map<int, pair<Contig*, int> >* GetEdge( int type );
	void SetCopyNum( int c );
	int GetCopyNum();
	void AddOccu();		// add one occurrence
	int GetOccu();
	void RemoveOccu();		// remove one occurrence
	void SetName( string s );
	void SetInScaffold();
	bool IfInScaffold();
	void AddGap( Gap *g );		// add a gap which contains this contig
	list<Gap*>* GetRelatedGaps();

	// vector related methods
	void SetVector( int start, int end, int ori );
	void SetIfPrintInVec( bool p );
	bool IfPrintInVec();
	void SetStepInVecGraph( int s );
	int GetStepInVecGraph();
	void SetIfVec( bool v );
	bool IfVec();
	int GetVecOri();
	int GetStartInVec();
	int GetEndInVec();

	// quadratic programming related
	void AddNewInEdgeVar( int x );
	void AddNewOutEdgeVar( int x );
	list<int>* GetNewInEdgeVar();
	list<int>* GetNewOutEdgeVar();
	void CombineVariables();		// add new variables to all variables
	list<int>* GetInEdgeVar();
	list<int>* GetOutEdgeVar();
	void ClearVar();

	// simplify graph
	void RemoveFromAllGaps();		// remove this node from all related gaps
	void AddCombinedNode( Contig *c, int direction, int ori );
	list<pair<string, string> >* GetCombinedNodes();

	// sequence
	void SetPlusSeq( string s );
	void SetMinusSeq( string s );
	string GetPlusSeq();
	string GetMinusSeq(); 

	bool CheckIfExtendRight( set<Gap*> *gaps );		// check if this contig is in scaffold and extend right
	bool CheckIfExtendLeft( set<Gap*> *gaps );		// check if this contig is in scaffold and extend left

private:
	void AddEdge( int contigID, Contig *contig, int size, map<int, pair<Contig*, int> > *edges );
};

